#include <libgen.h>
#include "server.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>

void send_file(char* filename, int sockfd, struct sockaddr_in fsock, int size)
{
  FILE *stream;
  char *file_content;
  struct stat sb;
  unsigned int msglength;

  if ((stream = fopen(filename, "r")) == NULL)
    {
      perror("fopen");
      exit(1);
    }

  if (stat(filename, &sb) == -1)
    {
      perror("stat");
      exit(1);
    }

  filename = basename(filename);

  msglength = sb.st_size + strlen("SEND  ") + strlen(filename);

  printf("sending %d\n", msglength);

  /* Build the request, with the following format, including whitespaces:
     "SEND filename file".  */
  file_content = calloc(msglength, 1);
  strcpy(file_content, "SEND");
  strcpy(file_content + strlen("SEND "), filename);
  fread(file_content + strlen("SEND  ") + strlen(filename), 1, sb.st_size, stream);

  sendto(sockfd, file_content, msglength, 0, (struct sockaddr *) &fsock, size);
  fflush(stream);
  fclose(stream);
  //remove(filename);
}

void self_check(int sockfd, struct sockaddr_in fsock, int size)
{
  char* msg = "SELFCHECK";

  printf("Requesting signature check on SAN.\n");
  sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr *) &fsock, size);
}

void read_dir(int sockfd, struct sockaddr_in fsock, int size)
{
  DIR *direct = opendir(CURRENT_DIR);
  char *filename;
  struct dirent *content = NULL;

  if (direct == NULL)
    {
      printf("invalid directory\n");
      exit(1);
    }

  while ((content = readdir(direct)) != NULL)
    {
      /* Do not send "." and ".." */
      if ((strcmp(content->d_name, "..") == 0)
          || (strcmp(content->d_name, ".")) == 0)
        continue;

      filename = calloc(strlen(CURRENT_DIR) + strlen(content->d_name), 1);
      strcat(filename, CURRENT_DIR);
      strcat(filename, content->d_name);
      printf("FILE : %s\n", filename);
      send_file(filename, sockfd, fsock, size);

      {
        /* Calculate the signature of the file, and send it separately. */
        char* md5writer = malloc(1024);
        sprintf(md5writer, "md5sum %1$s > %1$s.md5", filename);
        system(md5writer);
        send_file(strcat(strcat(calloc(1024, 1), filename), ".md5"), sockfd, fsock, size);
        free(md5writer);
      }

      {
        /* Remove the files that have been sent. */
        char* remover = malloc(1024);
        //sprintf(remover, "rm %1$s %1$s.md5", filename);
        sprintf(remover, "rm %1$s.md5", filename);
        system(remover);
        free(remover);
      }
      sleep(1);
    }
}

int main(int argc, char **argv)
{
  int fd = 0;
  int option = 1; // true
  int rsock;
  struct sockaddr_in ssock;
  unsigned int len = sizeof (ssock);
  unsigned int port;

  if (argc < 2)
    {
      printf("Usage: %s port\n", argv[0]);
      return 1;
    }
  port = atoi(argv[1]);

  fd = create_socket();
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(int)) < 0)
    {
      perror("Failed reusing socket.");
      return 1;
    }
  init_socket(fd, ssock, port);

  if (listen(fd, 5) != -1)
    {
      rsock = accept(fd, (struct sockaddr*) &ssock, &len);
      while (1)
        {
          /* FIXME: use an actual interface. */
          read_dir(rsock, ssock, len);
          self_check(rsock, ssock, len);
        }
    }

  close(fd);
  return 0;
}

/* Two simple socket functions, not much to see here. */
int create_socket(void)
{
  int sfd;

  if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
      perror("socket error");
      exit(1);
    }
  return sfd;
}

void init_socket(int sfd, struct sockaddr_in ssock, int port)
{
  ssock.sin_family = AF_INET;
  ssock.sin_addr.s_addr = htonl(INADDR_ANY);
  ssock.sin_port = htons(port);

  if (bind(sfd, (struct sockaddr *) &ssock, sizeof(ssock)) < 0)
    {
      perror("bind error");
      exit(1);;
    }
}

